#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cstring>
#include <map>
#include <set>
#include <vector>
#include <algorithm>

using namespace std;

string next_token(const string&, int&);
string bad_chars = "`1234567890-=~!@#$%^&*()_+[]"
                   "\\{}|;':\",./<>?\t\v\a\n ";

int MAXLENGTH = 10;
int MAXWORDLENGTH = 0;

struct isort
{
	bool operator()(string a, string b) const{
		return stricmp(a.c_str(), b.c_str()) == 0 
			? strcmp(a.c_str(), b.c_str()) < 0 
			: stricmp(a.c_str(), b.c_str()) < 0;}
};

typedef map<string, set<int>, isort> map_type;
typedef map_type::value_type element_type;

void parser(string s, int line, map_type &map);
void print(map_type &map, ostream &out);

int main(int argc, char* argv[])
{
	map_type map;
	if (argc == 2)
	{
		fstream file(argv[1]);
		int lineCount = 0;
		if (file.good())
		{
			while(!file.eof())
			{
				string tmp;
				getline(file, tmp);
				parser(tmp, ++lineCount, map);
			}
		}
	}
	else
	{
		string tmp;
		cout << "Enter a string to parse: ";
		cin >> tmp;
		parser(tmp, 1, map);
	}
	ofstream outFile;
	outFile.open("./Strings.out");
	if (!outFile.good())
		cout << "The file failed to open.";
	print(map, cout);
	cin.get();
}

string next_token(const string& s, int& pos)
{
    int begin = s.find_first_not_of(bad_chars,pos);
    int end = s.find_first_of(bad_chars,begin);
    pos = end;
    if (begin == string::npos)
        return string("");
    else if (end == string::npos)
        return s.substr(begin);
    else
        return s.substr(begin, end-begin);
}

void parser(string s, int line, map_type &map)
{
	int pos = 0;
	string token;
    while (!(token = next_token(s,pos)).empty())
	{
		map[token].insert(line);
		if (token.length() > MAXWORDLENGTH)
			MAXWORDLENGTH = token.length();
	}
}
void print(map_type &m, ostream &out)
{
	map_type::iterator p = m.begin();
	set <int>::iterator s1_Iter;
	out.setf(ios_base::left);
    while (p != m.end())
    {
		int count = 0;
        map_type::value_type elem = *p++;
		out << endl;
		out << setfill(' ') << setw(MAXWORDLENGTH) << elem.first;
		out << " : ";
		for ( s1_Iter = elem.second.begin( ); s1_Iter != elem.second.end( ); s1_Iter++ )
		{
			if (*s1_Iter != *s1_Iter -1)
			{
				if (count == 0)
				{
					out << *s1_Iter;
					count ++;
				}
				else if (count < 10)
				{
					out << ", " << *s1_Iter;
					count ++;
				}
				else
				{
					out << setfill(' ') << setw(MAXWORDLENGTH+1) << "\n";
					out << " : ";
					out << *s1_Iter;
					count = 1;
				}
			}
		}
    }
}